package physics;

import java.awt.Shape;
import java.awt.geom.AffineTransform;

public abstract class Obstacle implements Actor{

	
	private Coordinate location;
	private Shape shape;
	private double density;
	private double mass;
	private World world;
	private Vector vector;
	
	public Obstacle(Coordinate location,Shape bound,double mass){
		if (bound == null)
			throw new IllegalArgumentException("The bound can not be null.");
		this.location = location;
		setShape(calculateShapeLocation(bound));
		this.mass = mass;
		vector = new Vector(0, 0);
	}
	
	
	
	/**
	 * Set a new location for this obstacle.
	 * @param 	newLocation
	 * 				Coordinate of the new location.	
	 */
	public void setLocation(Coordinate newLocation){
		double newX =  newLocation.x - this.getLocation().x;
		double newY =  newLocation.y - this.getLocation().y;
		this.setShape(AffineTransform.getTranslateInstance(newX,newY).createTransformedShape(getShape()));
		this.location = newLocation;
	}
	
	/**
	 * @return The location of this obstacle.
	 */
	public Coordinate getLocation() {
		return location;
	}

	/**
	 * @return	The bound of this obstacle, represented by a shape.
	 */
	public Shape getShape() {
		return shape;
	}
	
	/**
	 * Set the shape of this object.
	 * @param shape
	 * 			The new shape.
	 */
	private void setShape(Shape shape){
		this.shape = shape;
	}
	
	/**
	 * Calculates the location of the given shape, centered around the location of this obstacle.
	 * @param 	p
	 * 				The shape to calculate the location for.
	 * @return	The shape centered around the location of this obstacle.
	 */
	private Shape calculateShapeLocation(Shape p){
		
		double newX = this.getLocation().x -p.getBounds().x- (p.getBounds().width / 2);
		double newY =  this.getLocation().y - p.getBounds().y -(p.getBounds().height / 2);
		return AffineTransform.getTranslateInstance(newX,newY).createTransformedShape(p);
	}

	/**
	 * @return	The mass density of this obstacle.
	 */
	public double getDensity() {
		return density;
	}

	/**
	 * @return	Mass of this obstacle.
	 */
	public double getMass() {
		return mass;
	}
	
	/**
	 * @return The vector acting on this obstacle.
	 */
	public Vector getVector(){
		return vector;
	}
	
	/**
	 * Set the vector acting on this obstacle.
	 * @param 	v
	 * 				The vector to act on this obstacle.
	 */
	protected void setVector(Vector v){
		this.vector = v;
	}

	
	public  abstract void  act();


	/**
	 * Set the world of this obstacle.
	 * @param 	w
	 * 				The world this obstacle is part of.
	 */
	void setWorld(World w) {
		this.world = w;
	}

	public World getWorld(){
		return this.world;
	}

	public boolean canHaveAsWorld(World w) {
		return w.hasObstacle(this);
	}

	
}
